/*
 * Rhy VSlider and HSlider
 *
 * @author Tristan Maindron
 * @dependencies rhy.core.wrapper, rhy.core.selector, rhy.core.config, rhy.core.view, rhy.extra.drag
 * 
 */

Rhy.extra.slider = {
    
    data: [],
    
    /*
     * First called, this function initializes the slider.
     */
    apply: function(trackDiv, config){
        
        var sliderDiv = $rh(".rhy-slider-thumb", trackDiv)[0];
        
        // Set configuration defaults for unspecified values.
        config = $r.cfg.manager.merge({
            mode: 'h',
            onSlide: function(){},
            onSlideBegin: function(){},
            onSlideEnd: function(){},
            value: 0,
            min: 0,
            max: 255,
            reverse: false,
            wasConverted: false
        }, config);
        
        // Store the slider for further operations.
        Rhy.extra.slider.data[$r.ex.slider.data.length] = {
            thumb: sliderDiv,
            track: trackDiv,
            config: config
        };

        // Build the view.
        $r.ex.slider.build(sliderDiv, trackDiv, config);
        
        // Memorize the slider id into the dom element for user access.
        sliderDiv.sliderId = $r.ex.slider.data.length - 1;
        trackDiv.sliderId = sliderDiv.sliderId;
        
        $r.ex.slider.computeFill(sliderDiv);
    },
    
    /*
     * This function has to be called on the slider's track or thumb every time a slider is unhidden.
     * Calling it on the track or the thumb makes no difference;
     */
    refresh: function(trackDiv){
        var data = Rhy.extra.slider.data[trackDiv.sliderId];
        var config = data.config;
        
        // If the component is not visible, don't refresh.
        if(!$r.vw.style.isVisible(data.thumb)){
            return;
        }
        
        // Override the config default value to set the current value. Avoid value loss on rebuild.
        config.value = data.thumb.rhySlideOffset;
        
        // Rebuild the view.
        $r.ex.slider.build(data.thumb, data.track, config);
        $r.ex.slider.computeFill(data.thumb);
    },
    
    setValue: function(div, value){
        var data = Rhy.extra.slider.data[div.sliderId];
        var config = data.config;
        config.wasConverted = false;
        config.value = value;
        $r.ex.slider.build(data.thumb, data.track, config);
        $r.ex.slider.refresh(data.thumb);
    },
    
    computeFill: function(sliderDiv){
        var data = Rhy.extra.slider.data[sliderDiv.sliderId];
        var config = data.config;
        
        var fill = $rh('.rhy-slider-fill', data.track)[0];

        if(typeof(fill) != "undefined"){
            var fs = fill.style;
            if(config.mode == 'h'){
                fs.height  = $r.vw.gp.getOffsetHeight(data.track) + 'px';
                
                if(config.reverse){
                    var width = $r.vw.gp.getOffsetWidth(data.track) - data.thumb.rhySlideOffset;
                    fs.width = width + 'px';
                    fs.position = 'absolute';
                    fs.marginLeft = ($r.vw.gp.getOffsetWidth(data.track) - width) + 'px';
                }  
                else{
                    fs.width = (data.thumb.rhySlideOffset + $r.vw.gp.getOffsetWidth(data.thumb)) + 'px';
                }
                
            }
            else{
                if(config.reverse){
                    var height = $r.vw.gp.getOffsetHeight(data.track) - data.thumb.rhySlideOffset;
                    fs.height = height + 'px';
                    fs.width  = $r.vw.gp.getOffsetWidth(data.track) + 'px';
                    fs.position = 'absolute';
                    fs.marginTop = ($r.vw.gp.getOffsetHeight(data.track) - height) + 'px';
                }  
                else{
                    fs.height = (data.thumb.rhySlideOffset + $r.vw.gp.getOffsetHeight(data.thumb)) + 'px';;
                }
                    
            }
        }
    },
    
    affectValues: function(sliderDiv, sMin, sMax, rMin, rMax, sCurrent, reverse){        
        sliderDiv.rhySlideOffset = sCurrent;
        sliderDiv.rhySlideValue = $r.ex.slider.computeRealValue(sMin, sMax, rMin, rMax, sCurrent, reverse);
    },
    
    // Builds up the slider real value.
    computeRealValue: function(sMin, sMax, rMin, rMax, sCurrent, reverse){
        
        if(reverse){
            var temp = rMin;
            rMin = rMax;
            rMax = temp;
        }
        
        var sSize = sMax - sMin;
        var rSize = rMax - rMin;
        
        var rCurrent = rSize * sCurrent / sSize + rMin;
       
        return rCurrent;
    },
    
    computeDisplayValue: function(sMin, sMax, rMin, rMax, rCurrent, reverse){
        if(reverse){
            var temp = rMin;
            rMin = rMax;
            rMax = temp;
        }
        
        var sSize = sMax - sMin;
        var rSize = rMax - rMin;
        
        var sCurrent = ((rCurrent - rMin) / rSize) * sSize;
        
        return sCurrent;
    },
    
    /*
     * Internal function for building the view. Not called externally.
     */
    build: function(sliderDiv, trackDiv, config){
        
        if(!$r.vw.style.isVisible(trackDiv)){
            return;
        }
        
        // Calculates the screen max and min coordinates for the thumb.
        // The drag and drop module only works on absolute position.
        var xmin = $r.vw.gp.getOffsetLeft(trackDiv);
        var xmax = xmin + $r.vw.gp.getOffsetWidth(trackDiv) - $r.vw.gp.getOffsetWidth(sliderDiv);
        
        var ymin = $r.vw.gp.getOffsetTop(trackDiv);
        var ymax = ymin + $r.vw.gp.getOffsetHeight(trackDiv) - $r.vw.gp.getOffsetHeight(sliderDiv);
        
        // Make sure the thumb position is absolute.
        sliderDiv.style.position = 'absolute';
        
        var displayValue;
        
        // Apply position to the thumb. Vertical or horizontal, it's the same: absolute min position + current slide value.
        if(config.mode == 'h'){
            sliderDiv.style.left = (xmin + config.value) + 'px';
            sliderDiv.style.top = ymin + 'px';
            var min = xmin;
            var max = xmax;
        }
        else{
            sliderDiv.style.top = (ymin + config.value) + 'px';
            sliderDiv.style.left = xmin + 'px';
            var min = ymin;
            var max = ymax;
        }
        
        if(config.wasConverted)
            displayValue = config.value;
        else
            displayValue = $r.ex.slider.computeDisplayValue(min, max, config.min, config.max, config.value, config.reverse);
        
        $r.ex.slider.affectValues(sliderDiv, min, max, config.min, config.max, displayValue, config.reverse);
        
        config.wasConverted = true;
        config.onSlide(sliderDiv);
        
        var onClick = function(e){
            var h = config.mode == 'h';
            
            var mouse = Rhy.extra.drag.mouseXY(e);
            
            var current = h ? mouse.x - $r.vw.gp.getOffsetLeft(trackDiv) - $r.vw.gp.getOffsetWidth(sliderDiv) : mouse.y - $r.vw.gp.getOffsetTop(trackDiv) - $r.vw.gp.getOffsetHeight(sliderDiv);
            var min = h ? xmin : ymin;
            var max = h ? xmax : ymax;
            
            current = Math.min(max, current);
            current = Math.max(0, current);
            
            $r.ex.slider.affectValues(sliderDiv, min, max, config.min, config.max, current, config.reverse);
            $r.ex.slider.refresh(sliderDiv);
        };
        
        if(trackDiv.rhyOnClick != null){
            $r.off(trackDiv, 'click', trackDiv.rhyOnClick);
        }
        
        $r.on(trackDiv, 'click', onClick);
        
        trackDiv.rhyOnClick = onClick;
        
        // Give the hand to the drag manager.
        $r.ex.drag.apply(sliderDiv, {
            axis: config.mode == 'h' ? 'x' : 'y',
            x : { min : xmin, max: xmax},
            y : { min : ymin, max: ymax},
            onDragBegin: function(){
                config.onSlideBegin(sliderDiv);
            },
            onDrop: function(){
                config.onSlideEnd(sliderDiv);
            },
            onDrag: function(){
                // When the slider is dragged, we get the drag absolute position.
                var e = Rhy.extra.drag.currentLocation;
                
                var h = config.mode == 'h';
                var min = h ? xmin : ymin;
                var max = h ? xmax : ymax;
                var current = h ? e.x - xmin : e.y - ymin;
                
                $r.ex.slider.affectValues(sliderDiv, min, max, config.min, config.max, current, config.reverse);
                
                $r.ex.slider.computeFill(sliderDiv);
                config.onSlide(sliderDiv);
            }
        });

    }
}